#include "printf.h"
#include "pmm.h"
#include "vmm.h"
#include "interrupt.h"
#include "clint.h"
#include "riscv.h"
#include "mmio.h"  // 新增：用于访问UART寄存器（内存映射IO）
#include <stdint.h>
#include <stddef.h>

// --------------------------
// 新增：UART寄存器定义（直接在main.c中声明，无需uart.h）
// QEMU的UART0（16550A兼容）寄存器地址映射
#define UART0_ADDR 0x10000000UL
#define UART_RHR (UART0_ADDR + 0x0)  // 接收保持寄存器（读）
#define UART_THR (UART0_ADDR + 0x0)  // 发送保持寄存器（写）
#define UART_LSR (UART0_ADDR + 0x5)  // 线路状态寄存器
#define UART_IER (UART0_ADDR + 0x1)  // 中断使能寄存器
#define UART_IIR (UART0_ADDR + 0x2)  // 中断识别寄存器

// UART线路状态寄存器（LSR）标志位
#define UART_LSR_RX_READY (1 << 0)  // 接收数据就绪（有数据可读）
#define UART_LSR_TX_EMPTY (1 << 5)  // 发送保持寄存器为空

// UART中断使能寄存器（IER）标志位
#define UART_IER_RX_INT (1 << 0)    // 使能接收中断

// --------------------------
// 原有延时函数（保留）
// --------------------------
void delay(int count) {
    for (int i = 0; i < count; i++) {
        for (int j = 0; j < 1000; j++) {
            __asm__ __volatile__("nop");
        }
    }
}

// --------------------------
// 时钟中断处理（保留并优化）
// --------------------------
static volatile int timer_irq_count = 0;
void timer_handler(void) {
    timer_irq_count++;
    if (timer_irq_count % 5 == 0) {
        printf("\n[时钟中断] 第%d次触发（约%d秒）\n", 
               timer_irq_count, timer_irq_count / 5);
    }
    clint_set_next_tick(r_mhartid());
}

// --------------------------
// 新增：UART功能函数（替代uart.h的作用）
// --------------------------
// 读取UART接收的字符（无数据时返回-1）
static int uart_getc(void) {
    // 检查接收缓冲区是否有数据
    if (mmio_read32(UART_LSR) & UART_LSR_RX_READY) {
        return mmio_read32(UART_RHR) & 0xFF;  // 返回8位字符
    } else {
        return -1;  // 无数据
    }
}

// 初始化UART中断（使能接收中断）
static void uart_init_irq(void) {
    // 使能UART接收中断（当有数据输入时触发中断）
    mmio_write32(UART_IER, UART_IER_RX_INT);
}

// 清除UART中断标志（通过读取IIR寄存器实现）
static void uart_clear_irq(void) {
    mmio_read32(UART_IIR);  // 读取中断识别寄存器可清除中断标志
}

// --------------------------
// 新增：UART中断处理函数
// --------------------------
static volatile int uart_irq_count = 0;
void uart_handler(void) {
    uart_irq_count++;
    int c = uart_getc();  // 读取接收的字符
    if (c != -1) {
        printf("\n[UART中断] 第%d次触发，收到字符: '%c' (ASCII: %d)\n", 
               uart_irq_count, c, c);
        // 回显字符（原样输出）
        uart_putc(c);
    }
    uart_clear_irq();  // 清除中断标志，避免重复触发
}

// --------------------------
// 虚拟地址访问测试（保留）
// --------------------------
void test_virtual_address_access() {
    void* phys_page = alloc_page();
    if (!phys_page) {
        printf("test_virtual_address_access: 分配物理页失败\n");
        return;
    }
    printf("\n=== 虚拟地址访问测试 ===\n");
    uint64_t pa = (uint64_t)phys_page;
    uint64_t va = KERNBASE + (pa - PHYSBASE);
    printf("物理页: PA = %p -> 虚拟地址: VA = %p\n", phys_page, (void*)va);
    printf("=== 虚拟地址访问测试结束 ===\n");
}

// --------------------------
// 主函数（新增UART中断注册）
// --------------------------
int main(void) {
    // 1. 启动信息与printf测试（保留）
    printf("RISC-V 操作系统启动...\n");
    printf("Hello, RISC-V OS!\n");
    printf("Decimal test: %d, %d, %d\n", 123, -456, 0);
    printf("Hex test: %x, %x\n", 0x1234, 0xABCD);
    printf("String test: %s\n", "This is a string");
    printf("Char test: %c, %c\n", 'A', 'Z');
    printf("Mixed test: %s = %d (0x%x)\n", "Answer", 42, 42);
    printf("Percent test: 100%% complete\n");
    
    // 2. 清屏测试（保留）
    printf("3秒后清屏...\n");
    delay(3000);
    clear_screen();
    printf("屏幕已清空！\n");
    
    // 3. 物理内存管理测试（保留）
    printf("\n=== 物理内存管理测试 ===\n");
    pmm_init((uint64_t)_end, PHYSTOP);
    printf("PMM初始化完成（内存范围：%p ~ %p）\n", (void*)_end, (void*)PHYSTOP);
    
    void* page1 = alloc_page();
    printf("分配单个页: %p %s\n", page1, page1 ? "（成功）" : "（失败）");
    
    void* pages = alloc_pages(5);
    printf("分配5个连续页: %p %s\n", pages, pages ? "（成功）" : "（失败）");
    
    size_t total, free;
    get_memory_info(&total, &free);
    printf("内存状态: 总内存 %d KB, 空闲内存 %d KB\n", total/1024, free/1024);
    
    if (page1) free_page(page1);
    printf("释放单个页: %p（完成）\n", page1);
    if (pages) free_pages(pages, 5);
    printf("释放5个连续页: %p（完成）\n", pages);
    
    get_memory_info(&total, &free);
    printf("释放后内存状态: 总内存 %d KB, 空闲内存 %d KB\n", total/1024, free/1024);
    
    void* large_alloc = alloc_pages(100);
    if (large_alloc) {
        printf("分配100个连续页: %p（成功）\n", large_alloc);
        free_pages(large_alloc, 100);
    } else {
        printf("分配100个连续页: 失败\n");
    }
    printf("=== 物理内存管理测试结束 ===\n");
    
    // 4. 虚拟内存初始化（保留）
    printf("\n=== 虚拟内存初始化 ===\n");
    kvm_init();
    printf("=== 虚拟内存已启用 ===\n");
    
    // 5. 内核页表映射验证（保留）
    printf("\n=== 内核页表映射验证 ===\n");
    pte_t* text_pte = walk_lookup(kernel_pagetable, (uint64_t)_text + (KERNBASE - PHYSBASE));
    if (text_pte && (*text_pte & (PTE_V | PTE_R | PTE_X)) == (PTE_V | PTE_R | PTE_X)) {
        printf("代码段映射验证: 成功（R+X权限）\n");
    } else {
        printf("代码段映射验证: 失败\n");
    }
    
    pte_t* uart_pte = walk_lookup(kernel_pagetable, UART0);
    if (uart_pte && (*uart_pte & (PTE_V | PTE_R | PTE_W)) == (PTE_V | PTE_R | PTE_W)) {
        printf("UART设备映射验证: 成功（R+W权限）\n");
    } else {
        printf("UART设备映射验证: 失败\n");
    }
    printf("=== 内核页表映射验证结束 ===\n");
    
    // 5.2 虚拟地址读写测试（保留）
    test_virtual_address_access();
    
    // 5.3 打印页表结构（保留）
    printf("\n=== 内核页表结构 ===\n");
    dump_pagetable(kernel_pagetable, 0);
    
    // 6. 中断处理测试（新增UART中断注册）
    printf("\n=== 中断处理测试 ===\n");
    trap_init();
    printf("中断系统初始化完成\n");
    
    // 6.1 注册并启用时钟中断（保留）
    int timer_reg = register_interrupt(IRQ_TIMER, timer_handler, IRQ_PRIORITY_3);
    if (timer_reg != 0) {
        printf("注册时钟中断失败！错误码: %d\n", timer_reg);
    } else {
        enable_interrupt(IRQ_TIMER);
        printf("时钟中断已启用（每≈0.2秒触发一次）\n");
    }
    
    // 6.2 新增：注册并启用UART中断
    int uart_reg = register_interrupt(IRQ_UART, uart_handler, IRQ_PRIORITY_5);  // 更高优先级
    if (uart_reg != 0) {
        printf("注册UART中断失败！错误码: %d\n", uart_reg);
    } else {
        uart_init_irq();  // 初始化UART硬件中断（使能接收中断）
        enable_interrupt(IRQ_UART);
        printf("UART中断已启用（输入字符可触发）\n");
    }
    printf("=== 中断处理测试启动完成 ===\n");
    
    // 7. 内核主循环（优化状态显示）
    printf("\n内核运行中...（按Ctrl+C退出QEMU，可输入字符测试UART中断）\n");
    while (1) {
        wfi();  // 等待中断唤醒
        static int loop_count = 0;
        if (++loop_count % 1000 == 0) {
            printf("[主循环] 运行中（循环计数: %d，时钟中断: %d次，UART中断: %d次）\n",
                   loop_count, timer_irq_count, uart_irq_count);
        }
    }
 
    return 0;
}
